import ustruct
import modbus as mb
import utime as time
import urandom

# mb.init("modbus_485")
class ModeBusRtu(object):
    def __init__(self):
        mb.init("modbus_485")
       
        self.dev_addr = 1
        self.relay_add = 2
        self.voltage_add = 3
        self.volt_channel = 8

    def read_temp_hum_bar(self):
        """
        brief: 读取温度、湿度、气压数据
        return: 返回数据列表
        """
        value = bytearray(12)
        result = [0]*3
        ret = mb.readHoldingRegisters(self.dev_addr, 0, 3, value, 200)
        if ret[0] != 0:
            print("Error: %d" % ret[0])
            return [99]*3
        data= ustruct.unpack('hhh',value)
        # print(data)
        temp = (data[0]/100)-40
        humidity = data[1]/100
        baro = data[2]/100
        # print(ret)
        # print(value)
        result = [temp,humidity,baro]
        return result

    def turn_on_relay_one(self, relay_num):
        """
        brief: 打开1-3其中一个继电器开关
        """
        if relay_num == 1:         
            ret = mb.writeHoldingRegister(self.relay_add, 0, 1, 200)
            if ret[0] < 0:
                print("Error: %d" % ret[0])
        if relay_num == 2:         
            ret = mb.writeHoldingRegister(self.relay_add, 1, 1, 200)
            if ret[0] < 0:
                print("Error: %d" % ret[0])
        if relay_num == 3:         
            ret = mb.writeHoldingRegister(self.relay_add, 2, 1, 200)
            if ret[0] < 0:
                print("Error: %d" % ret[0])

    def turn_off_relay_one(self, relay_num):
        """
        brief: 关闭1-3其中一个继电器开关
        """
        if relay_num == 1:         
            ret = mb.writeHoldingRegister(self.relay_add, 0, 0, 200)
            if ret[0] < 0:
                print("Error: %d" % ret[0])
        if relay_num == 2:         
            ret = mb.writeHoldingRegister(self.relay_add, 1, 0, 200)
            if ret[0] < 0:
                print("Error: %d" % ret[0])
        if relay_num == 3:         
            ret = mb.writeHoldingRegister(self.relay_add, 2, 0, 200)
            if ret[0] < 0:
                print("Error: %d" % ret[0])

    def turn_on_relay_all(self):
        ret = mb.writeHoldingRegister(self.relay_add, 52, 1, 200)
        if ret[0] < 0:
            print("Error: %d" % ret[0])
        
    def turn_off_relay_all(self):  
        ret = mb.writeHoldingRegister(self.relay_add, 52, 0, 200)
        if ret[0] < 0:
            print("Error: %d" % ret[0])
    # 获取继电器状态
    def get_relay_status(self):
        value = bytearray(6)
        # 发送命令 02 03 00 00 00 03 05 F8   全开 02 03 06 00 01 00 01 00 01 98 45
        ret = mb.readHoldingRegisters(self.relay_add, 0, 3, value, 200)
        if ret[0] < 0:
            print("Error: %d" % ret[0])
            return 6,6,6
        data= ustruct.unpack('hhh',value)
        return data[0],data[1],data[2]
    

    # 8通道模拟信号输入
    def read_volt_all_channel(self):
        '''
        brief: 获取所有模拟通道数据
        return: 返回列表数据
        '''
        value = bytearray(16)
        result = [0]*self.volt_channel
        ret = mb.readInputRegisters(self.voltage_add,0,8,value,200)
        # 数据解析后为10进制数据，第一位为小数点位数，如31023，实际值1.023V
        if ret[0] != 0:
            print("Error: %d" % ret[0])
            return [99]*self.volt_channel
        data = ustruct.unpack('HHHHHHHH',value)
        i = 0
        while i < len(data):
            num = data[i]
            if num == 0:
                result[i] = 0
            else:
                decimal_place = num // 10000
                valid_data = num % 10000
                actual_data = valid_data * (10**(-decimal_place))
                result[i] = actual_data
            i += 1
        return result  #分别对应模拟通道1-8

    def read_soil_sensor(self,addr=1,retries=2, delay_ms=100):
        '''
        brief: 读取水分传感器数据
        return: 返回列表数据
        '''
        time.sleep(0.2)
        readBuf = bytearray(4)
        for attempt in range(retries):
            ret = mb.readHoldingRegisters(addr, 0, 2, readBuf, 2000)
            if ret[0] == 0:
                # 读取成功
                data = ustruct.unpack('HH', readBuf)
                return data
            else:
                print("Error reading sensor at address %d: %d (Attempt %d)" % (addr, ret[0], attempt + 1))
                if attempt < retries - 1:
                    time.sleep(delay_ms / 1000.0) # 重试前延时
        # 所有重试都失败
        print("Failed to read sensor at address %d after %d attempts." % (addr, retries))
        return (999,999) # 返回一个特定的错误码

    def read_virtual_soil_sensor(self, addr=1, retries=2, delay_ms=100):
        '''
        brief: 返回虚拟的水分传感器数据（用于测试）
        return: 返回列表数据，格式与read_soil_sensor相同
        '''
        time.sleep(0.2)  # 模拟读取延时
        soil = urandom.randint(20, 80)  # 湿度20%-80%
        temperature = urandom.randint(150, 350)  # 温度15-35度的10倍表示
        return (soil, temperature)




  

    
    
    